package org.Yiran.timetale_re.entity.rune;

import net.minecraft.core.particles.ItemParticleOption;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.NetworkHooks;
import net.minecraftforge.network.PacketDistributor;
import org.Yiran.timetale_re.entity.EntityRegister;
import org.Yiran.timetale_re.item.ItemsRegister;
import org.Yiran.timetale_re.item.rune.base.RuneAbility;
import org.Yiran.timetale_re.item.rune.base.RuneItem;
import org.Yiran.timetale_re.item.rune.base.RuneRegistry;
import org.Yiran.timetale_re.item.rune.type.functional.base.FunctionalRune;
import org.Yiran.timetale_re.network.NetworkChannel;
import org.Yiran.timetale_re.network.SCResponsePacket;
import org.jetbrains.annotations.NotNull;

import java.util.UUID;

/**
 * 飞行符文实体类
 * <p>
 * 该类表示一个在世界中飞行的符文物品实体，具有以下功能：
 * 1. 从起始位置飞向目标位置的动画效果
 * 2. 飞行过程中生成粒子效果
 * 3. 飞行结束后执行符文效果
 * 4. 客户端与服务端同步机制
 * </p>
 */
public class FlyingRuneEntity extends Entity {
    
    // ============================== 实体数据访问器 ==============================
    
    private static final EntityDataAccessor<ItemStack> DATA_ITEM = SynchedEntityData.defineId(FlyingRuneEntity.class, EntityDataSerializers.ITEM_STACK);
    private static final EntityDataAccessor<String> RUNE_TYPE = SynchedEntityData.defineId(FlyingRuneEntity.class, EntityDataSerializers.STRING);

    // ============================== 实例变量 ==============================
    
    private Vec3 startPosition;        // 起始位置
    private Vec3 targetPosition;       // 目标位置
    public int flightTime = 0;         // 飞行时间
    private final int maxFlightTime = 52; // 飞行持续时间(tick)
    private boolean needSync = true;   // 是否需要同步
    private long creationTime;         // 创建时间
    private String runeType = "";      // 符文类型
    private UUID ownerUUID;            // 所有者UUID

    // ============================== 构造方法 ==============================
    
    /**
     * 构造函数 - 用于实体注册
     * 
     * @param entityType 实体类型
     * @param level 世界对象
     */
    public FlyingRuneEntity(EntityType<? extends FlyingRuneEntity> entityType, Level level) {
        super(entityType, level);
        this.noPhysics = true;
    }

    /**
     * 构造函数 - 创建飞行符文实体
     * 
     * @param level 世界对象
     * @param startPos 起始位置
     * @param targetPos 目标位置
     * @param runeStack 符文物品堆
     */
    public FlyingRuneEntity(Level level, Vec3 startPos, Vec3 targetPos, ItemStack runeStack) {
        super(EntityRegister.FLYING_RUNE.get(), level);
        this.startPosition = startPos;
        this.setPos(startPos.x, startPos.y, startPos.z);
        this.targetPosition = targetPos;
        this.entityData.set(DATA_ITEM, runeStack.copy());
        this.runeType = RuneItem.getRuneType(runeStack);
        this.entityData.set(RUNE_TYPE, this.runeType);
        this.needSync = true;
        this.creationTime = level.getGameTime();
    }

    // ============================== 数据同步方法 ==============================
    
    /**
     * 定义同步数据
     * <p>
     * 初始化实体的同步数据，包括符文物品和符文类型
     * </p>
     */
    @Override
    protected void defineSynchedData() {
        this.entityData.define(DATA_ITEM, ItemStack.EMPTY);
        this.entityData.define(RUNE_TYPE, "");
    }

    // ============================== 防火特性方法 ==============================
    
    /**
     * 添加防火特性 - 使实体无法被火焰点燃
     * 
     * @return true表示实体对火焰免疫
     */
    @Override
    public boolean fireImmune() {
        return true;
    }

    /**
     * 添加防火特性 - 防止实体着火
     * 
     * @return false表示实体不会着火
     */
    @Override
    public boolean isOnFire() {
        return false;
    }

    // ============================== 实体更新方法 ==============================
    
    /**
     * 实体更新方法
     * <p>
     * 每tick调用一次，处理飞行逻辑和动画效果
     * </p>
     */
    @Override
    public void tick() {
        super.tick();

        // 添加超时保护，防止实体永久存在
        if (!this.level().isClientSide()) {
            long currentTime = this.level().getGameTime();
            if (currentTime - this.creationTime > this.maxFlightTime * 2) { // 给予一定的缓冲时间
                // 如果飞行时间过长，直接完成飞行并执行效果
                this.onFlightComplete();
                this.discard(); // 移除实体
                return;
            }
        }

        if (this.level().isClientSide) {
            // 客户端处理飞行动画
            handleFlightAnimation();
        } else {
            // 服务端处理飞行逻辑
            handleFlightLogic();

            // 同步到客户端
            if (needSync) {
                syncToClient();
                needSync = false;
            }
        }
    }

    // ============================== 位置计算方法 ==============================
    
    /**
     * 根据飞行时间和起始/目标位置计算当前位置
     */
    private void updatePositionFromFlightTime() {
        if (startPosition == null || targetPosition == null) return;

        // 根据创建时间计算当前飞行时间
        long currentTime = this.level().getGameTime();
        flightTime = (int) (currentTime - creationTime);

        double progress = Math.min((double) flightTime / maxFlightTime, 1.0);

        // 计算当前位置 (从玩家位置飞向目标位置)
        Vec3 currentPos = startPosition.lerp(targetPosition, progress);
        this.setPos(currentPos.x, currentPos.y, currentPos.z);
    }

    /**
     * 初始化飞行状态
     */
    private void initializeFlight() {
        if (!this.level().isClientSide() && startPosition != null && targetPosition != null) {
            updatePositionFromFlightTime();
        }
    }

    // ============================== 动画处理方法 ==============================
    
    /**
     * 处理客户端飞行动画
     */
    private void handleFlightAnimation() {
        if (startPosition == null || targetPosition == null) return;

        updatePositionFromFlightTime();

        // 每10tick生成一次粒子效果
        if (flightTime % 10 == 0) {
            // 在客户端生成飞行过程中的粒子效果
            spawnFlightParticles(this.position());
        }

        // 飞行结束处理
        if (flightTime >= maxFlightTime) {
            // 飞行结束，播放音效并移除实体
            this.level().playLocalSound(this.getX(), this.getY(), this.getZ(),
                    SoundEvents.GLASS_BREAK, SoundSource.PLAYERS,
                    1.0F, 1.0F, false);

            // 生成破碎粒子效果
            spawnBreakParticles();

            this.discard();
        }
    }

    /**
     * 处理服务端飞行逻辑
     */
    private void handleFlightLogic() {
        if (startPosition == null || targetPosition == null) return;

        flightTime++;
        double progress = Math.min((double) flightTime / maxFlightTime, 1.0);

        // 计算当前位置 (从玩家位置飞向目标位置)
        Vec3 currentPos = startPosition.lerp(targetPosition, progress);
        this.setPos(currentPos.x, currentPos.y, currentPos.z);

        // 每10tick发送一次粒子效果包（降低频率以优化性能）
        if (flightTime % 10 == 0) {
            // 发送统一动画数据包到所有跟踪该实体的客户端
            NetworkChannel.CHANNEL.send(
                    PacketDistributor.TRACKING_ENTITY.with(() -> this),
                    new SCResponsePacket.RunePacket(
                            1, // 飞行过程粒子效果类型
                            this.getId(),
                            currentPos,
                            this.getRuneStack(),
                            1 // 粒子数量
                    )
            );
        }

        // 飞行结束处理
        if (flightTime >= maxFlightTime) {
            // 触发飞行完成事件
            onFlightComplete();

            // 发送破碎粒子效果包
            NetworkChannel.CHANNEL.send(
                    PacketDistributor.TRACKING_ENTITY.with(() -> this),
                    new SCResponsePacket.RunePacket(
                            0, // 符文破碎粒子效果类型
                            this.getId(),
                            this.position(),
                            ItemStack.EMPTY,
                            0
                    )
            );

            this.discard();
        }
    }

    // ============================== 粒子效果方法 ==============================
    
    /**
     * 在客户端生成飞行过程中的粒子效果
     */
    private void spawnFlightParticles(Vec3 position) {
        if (this.level().isClientSide) {
            ItemStack stack = this.getRuneStack();
            if (!stack.isEmpty()) {
                for (int i = 0; i < 1; i++) {
                    // 使用附魔台符文粒子效果替代物品破碎粒子效果
                    this.level().addParticle(
                            ParticleTypes.ENCHANT,
                            position.x + (this.level().random.nextDouble() - 0.5) * 0.5D,
                            position.y + (this.level().random.nextDouble() - 0.5) * 0.5D,
                            position.z + (this.level().random.nextDouble() - 0.5) * 0.5D,
                            (this.level().random.nextDouble() - 0.5) * 0.1D,
                            (this.level().random.nextDouble() - 0.5) * 0.1D,
                            (this.level().random.nextDouble() - 0.5) * 0.1D
                    );
                }
            }
        }
    }

    /**
     * 在客户端生成符文破碎粒子效果
     */
    private void spawnBreakParticles() {
        if (this.level().isClientSide) {
            ItemStack stack = this.getRuneStack();
            if (!stack.isEmpty()) {
                for (int i = 0; i < 8; i++) {
                    this.level().addParticle(
                            new ItemParticleOption(ParticleTypes.ITEM, stack),
                            this.getX(), this.getY(), this.getZ(),
                            this.level().random.nextGaussian() * 0.1D,
                            this.level().random.nextGaussian() * 0.1D,
                            this.level().random.nextGaussian() * 0.1D
                    );
                }
            }
        }
    }

    // ============================== 飞行完成方法 ==============================
    
    /**
     * 飞行动画完成时调用此方法
     * <p>
     * 可以被子类重写以执行特定逻辑，此处执行符文效果
     * </p>
     */
    public void onFlightComplete() {
        // 如果实体有所有者和符文类型信息，尝试执行对应的符文效果
        if (this.ownerUUID != null && !this.runeType.isEmpty() && !this.level().isClientSide()) {
            // 获取玩家实体
            Player player = null;
            for (Player p : this.level().players()) {
                if (p.getUUID().equals(this.ownerUUID)) {
                    player = p;
                    break;
                }
            }

            // 如果找到了玩家且符文类型有效，执行对应的效果
            if (player != null) {
                RuneAbility ability = RuneRegistry.getRuneAbility(this.runeType);
                if (ability instanceof FunctionalRune functionalRune) {
                    // 创建一个临时的符文物品来执行效果
                    ItemStack runeStack = new ItemStack(ItemsRegister.RUNE.get());
                    RuneItem.setRuneType(runeStack, this.runeType);

                    // 执行符文效果
                    try {
                        functionalRune.executeRuneEffect(runeStack, this.level(), player);
                    } catch (Exception e) {
                        // 忽略异常，防止崩溃
                    }
                }
            }
        }
    }

    // ============================== 数据保存方法 ==============================
    
    /**
     * 从NBT标签读取额外的实体数据
     * 
     * @param tag NBT标签
     */
    @Override
    protected void readAdditionalSaveData(CompoundTag tag) {
        // 读取符文物品数据
        if (tag.contains("Item")) {
            this.entityData.set(DATA_ITEM, ItemStack.of(tag.getCompound("Item")));
        }
        if (tag.contains("RuneType")) {
            this.runeType = tag.getString("RuneType");
            this.entityData.set(RUNE_TYPE, this.runeType);
        }
        if (tag.contains("StartX")) {
            this.startPosition = new Vec3(
                    tag.getDouble("StartX"),
                    tag.getDouble("StartY"),
                    tag.getDouble("StartZ")
            );
        }
        if (tag.contains("TargetX")) {
            this.targetPosition = new Vec3(
                    tag.getDouble("TargetX"),
                    tag.getDouble("TargetY"),
                    tag.getDouble("TargetZ")
            );
        }
        this.flightTime = tag.getInt("FlightTime");
        if (tag.contains("CreationTime")) {
            this.creationTime = tag.getLong("CreationTime");
        }
        if (tag.contains("OwnerUUID")) {
            this.ownerUUID = UUID.fromString(tag.getString("OwnerUUID"));
        }

        // 初始化飞行状态
        initializeFlight();
    }

    /**
     * 将额外的实体数据写入NBT标签
     * 
     * @param tag NBT标签
     */
    @Override
    protected void addAdditionalSaveData(CompoundTag tag) {
        tag.put("Item", this.entityData.get(DATA_ITEM).save(new CompoundTag()));
        tag.putString("RuneType", this.runeType);
        tag.putString("RuneTypeData", this.entityData.get(RUNE_TYPE));
        if (startPosition != null) {
            tag.putDouble("StartX", startPosition.x);
            tag.putDouble("StartY", startPosition.y);
            tag.putDouble("StartZ", startPosition.z);
        }
        if (targetPosition != null) {
            tag.putDouble("TargetX", targetPosition.x);
            tag.putDouble("TargetY", targetPosition.y);
            tag.putDouble("TargetZ", targetPosition.z);
        }
        tag.putInt("FlightTime", this.flightTime);
        tag.putLong("CreationTime", this.creationTime);
        if (this.ownerUUID != null) {
            tag.putString("OwnerUUID", this.ownerUUID.toString());
        }
    }

    // ============================== 网络同步方法 ==============================
    
    /**
     * 获取实体生成数据包
     * 
     * @return 实体生成数据包
     */
    @Override
    public @NotNull Packet<ClientGamePacketListener> getAddEntityPacket() {
        return NetworkHooks.getEntitySpawningPacket(this);
    }

    /**
     * 获取符文物品堆
     * 
     * @return 符文物品堆
     */
    public ItemStack getRuneStack() {
        return this.entityData.get(DATA_ITEM);
    }

    /**
     * 从服务端同步数据到客户端
     */
    private void syncToClient() {
        if (!this.level().isClientSide && this.startPosition != null && this.targetPosition != null) {
            // 发送同步数据包到跟踪此实体的客户端
            net.minecraftforge.network.PacketDistributor.PacketTarget target =
                    net.minecraftforge.network.PacketDistributor.TRACKING_ENTITY.with(() -> this);
            NetworkChannel.CHANNEL.send(
                    target,
                    new SCResponsePacket.RunePacket(
                            this.getId(),
                            this.startPosition,
                            this.targetPosition,
                            this.flightTime,
                            this.creationTime
                    )
            );
        }
    }

    /**
     * 设置从服务端同步过来的数据
     * 
     * @param startPosition 起始位置
     * @param targetPosition 目标位置
     * @param flightTime 飞行时间
     * @param creationTime 创建时间
     */
    public void setSyncData(Vec3 startPosition, Vec3 targetPosition, int flightTime, long creationTime) {
        this.startPosition = startPosition;
        this.targetPosition = targetPosition;
        this.flightTime = flightTime;
        this.creationTime = creationTime;

        // 更新当前位置
        updatePositionFromFlightTime();
    }

    // ============================== 渲染辅助方法 ==============================
    
    /**
     * 提供旋转角度给渲染器使用（通过插值计算）
     * 
     * @param partialTicks 部分tick值，用于平滑动画
     * @return 旋转角度（yaw）
     */
    public float getRotationYaw(float partialTicks) {
        // 根据创建时间计算当前飞行时间（包括partialTicks）
        long currentTime = this.level().getGameTime();
        float currentFlightTime = (float) (currentTime - creationTime) + partialTicks;

        // 使用指数函数计算当前旋转角度: 初始速度2，每tick按指数增长
        float totalRotation = 0;
        for (int i = 0; i < currentFlightTime; i++) {
            totalRotation += 2.0f * (float) Math.pow(1.1f, i);
        }

        // 处理partialTicks部分
        if (currentFlightTime > (int)currentFlightTime) {
            float fraction = currentFlightTime - (int)currentFlightTime;
            float nextRotationSpeed = 2.0f * (float) Math.pow(1.1f, (int)currentFlightTime);
            totalRotation += nextRotationSpeed * fraction;
        }

        return totalRotation;
    }

    // ============================== Getter和Setter方法 ==============================
    
    public Vec3 getStartPosition() {
        return startPosition;
    }

    public Vec3 getTargetPosition() {
        return targetPosition;
    }

    public long getCreationTime() {
        return creationTime;
    }

    public void setOwner(Player player) {
        this.ownerUUID = player.getUUID();
    }

    public UUID getOwnerUUID() {
        return this.ownerUUID;
    }

    public String getRuneType() {
        return this.runeType;
    }

    public void setRuneType(String type) {
        this.runeType = type;
    }
}